{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Deep Learning Models -- A collection of various deep learning architectures, models, and tips for TensorFlow and PyTorch in Jupyter Notebooks.\n",
    "- Author: Sebastian Raschka\n",
    "- GitHub Repository: https://github.com/rasbt/deeplearning-models"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sebastian Raschka \n",
      "\n",
      "CPython 3.7.1\n",
      "IPython 7.2.0\n",
      "\n",
      "torch 1.0.0\n"
     ]
    }
   ],
   "source": [
    "%load_ext watermark\n",
    "%watermark -a 'Sebastian Raschka' -v -p torch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Model Zoo -- Using PyTorch Dataset Loading Utilities for Custom Datasets (Cropped Street View Hous Numbers, SVHN)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook provides an example for how to load an image dataset, stored as individual PNG files, using PyTorch's data loading utilities. For a more in-depth discussion, please see the official\n",
    "\n",
    "- [Data Loading and Processing Tutorial](http://pytorch.org/tutorials/beginner/data_loading_tutorial.html)\n",
    "- [torch.utils.data](http://pytorch.org/docs/master/data.html) API documentation\n",
    "\n",
    "In this example, we are using the cropped version of the **Street View House Numbers (SVHN) Dataset**, which is available at http://ufldl.stanford.edu/housenumbers/. \n",
    "\n",
    "To execute the following examples, you need to download the 2 \".mat\" files \n",
    "\n",
    "- [train_32x32.mat](http://ufldl.stanford.edu/housenumbers/train_32x32.mat) (ca. 182 Mb, 73,257 images)\n",
    "- [test_32x32.mat](http://ufldl.stanford.edu/housenumbers/test_32x32.mat) (ca. 65 Mb, 26,032 images)\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Imports"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import os\n",
    "\n",
    "import torch\n",
    "from torch.utils.data import Dataset\n",
    "from torch.utils.data import DataLoader\n",
    "from torchvision import transforms\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "from PIL import Image\n",
    "import scipy.io as sio\n",
    "import imageio"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Dataset"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following function will convert the images from \".mat\" into individual \".png\" files. In addition, we will create CSV contained the image paths and associated class labels."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_pngs(main_dir, mat_file, label):\n",
    "    \n",
    "    if not os.path.exists(main_dir):\n",
    "        os.mkdir(main_dir)\n",
    "        \n",
    "    sub_dir = os.path.join(main_dir, label)\n",
    "    if not os.path.exists(sub_dir):\n",
    "        os.mkdir(sub_dir)\n",
    "\n",
    "    data = sio.loadmat(mat_file)\n",
    "\n",
    "    X = np.transpose(data['X'], (3, 0, 1, 2))\n",
    "    y = data['y'].flatten()\n",
    "\n",
    "    with open(os.path.join(main_dir, '%s_labels.csv' % label), 'w') as out_f:\n",
    "        for i, img in enumerate(X):\n",
    "            file_path = os.path.join(sub_dir, str(i) + '.png')\n",
    "            imageio.imwrite(os.path.join(file_path),\n",
    "                            img)\n",
    "\n",
    "            out_f.write(\"%d.png,%d\\n\" % (i, y[i]))\n",
    "\n",
    "            \n",
    "make_pngs(main_dir='svhn_cropped',\n",
    "          mat_file='train_32x32.mat',\n",
    "          label='train')\n",
    "    \n",
    "    \n",
    "make_pngs(main_dir='svhn_cropped',\n",
    "          mat_file='test_32x32.mat',\n",
    "          label='test')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>1</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0.png</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1.png</th>\n",
       "      <td>9</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2.png</th>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3.png</th>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4.png</th>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       1\n",
       "0       \n",
       "0.png  1\n",
       "1.png  9\n",
       "2.png  2\n",
       "3.png  3\n",
       "4.png  2"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.read_csv('svhn_cropped/train_labels.csv', header=None, index_col=0)\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>1</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0.png</th>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1.png</th>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2.png</th>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3.png</th>\n",
       "      <td>10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4.png</th>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "        1\n",
       "0        \n",
       "0.png   5\n",
       "1.png   2\n",
       "2.png   1\n",
       "3.png  10\n",
       "4.png   6"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.read_csv('svhn_cropped/test_labels.csv', header=None, index_col=0)\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Implementing a Custom Dataset Class"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we implement a custom `Dataset` for reading the images. The `__getitem__` method will\n",
    "\n",
    "1. read a single image from disk based on an `index` (more on batching later)\n",
    "2. perform a custom image transformation (if a `transform` argument is provided in the `__init__` construtor)\n",
    "3. return a single image and it's corresponding label"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class SVHNDataset(Dataset):\n",
    "    \"\"\"Custom Dataset for loading cropped SVHN images\"\"\"\n",
    "    \n",
    "    def __init__(self, csv_path, img_dir, transform=None):\n",
    "    \n",
    "        df = pd.read_csv(csv_path, index_col=0, header=None)\n",
    "        self.img_dir = img_dir\n",
    "        self.csv_path = csv_path\n",
    "        self.img_names = df.index.values\n",
    "        self.y = df[1].values\n",
    "        self.transform = transform\n",
    "\n",
    "    def __getitem__(self, index):\n",
    "        img = Image.open(os.path.join(self.img_dir,\n",
    "                                      self.img_names[index]))\n",
    "        \n",
    "        if self.transform is not None:\n",
    "            img = self.transform(img)\n",
    "        \n",
    "        label = self.y[index]\n",
    "        return img, label\n",
    "\n",
    "    def __len__(self):\n",
    "        return self.y.shape[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we have created our custom Dataset class, let us add some custom transformations via the `transforms` utilities from `torchvision`, we\n",
    "\n",
    "1. normalize the images (here: dividing by 255)\n",
    "2. converting the image arrays into PyTorch tensors\n",
    "\n",
    "Then, we initialize a Dataset instance for the training images using the 'quickdraw_png_set1_train.csv' label file (we omit the test set, but the same concepts apply).\n",
    "\n",
    "Finally, we initialize a `DataLoader` that allows us to read from the dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Note that transforms.ToTensor()\n",
    "# already divides pixels by 255. internally\n",
    "\n",
    "custom_transform = transforms.Compose([#transforms.Grayscale(),                                       \n",
    "                                       #transforms.Lambda(lambda x: x/255.),\n",
    "                                       transforms.ToTensor()])\n",
    "\n",
    "train_dataset = SVHNDataset(csv_path='svhn_cropped/train_labels.csv',\n",
    "                              img_dir='svhn_cropped/train',\n",
    "                              transform=custom_transform)\n",
    "\n",
    "test_dataset = SVHNDataset(csv_path='svhn_cropped/test_labels.csv',\n",
    "                             img_dir='svhn_cropped/test',\n",
    "                             transform=custom_transform)\n",
    "\n",
    "BATCH_SIZE=128\n",
    "\n",
    "\n",
    "train_loader = DataLoader(dataset=train_dataset,\n",
    "                          batch_size=BATCH_SIZE,\n",
    "                          shuffle=True,\n",
    "                          num_workers=4)\n",
    "\n",
    "test_loader = DataLoader(dataset=test_dataset,\n",
    "                         batch_size=BATCH_SIZE,\n",
    "                         shuffle=False,\n",
    "                         num_workers=4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That's it, now we can iterate over an epoch using the train_loader as an iterator and use the features and labels from the training dataset for model training:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Iterating Through the Custom Dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 1 | Batch index: 0 | Batch size: 128\n",
      "Epoch: 2 | Batch index: 0 | Batch size: 128\n"
     ]
    }
   ],
   "source": [
    "device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n",
    "torch.manual_seed(0)\n",
    "\n",
    "num_epochs = 2\n",
    "for epoch in range(num_epochs):\n",
    "\n",
    "    for batch_idx, (x, y) in enumerate(train_loader):\n",
    "        \n",
    "        print('Epoch:', epoch+1, end='')\n",
    "        print(' | Batch index:', batch_idx, end='')\n",
    "        print(' | Batch size:', y.size()[0])\n",
    "        \n",
    "        x = x.to(device)\n",
    "        y = y.to(device)\n",
    "        break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Just to make sure that the batches are being loaded correctly, let's print out the dimensions of the last batch:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([128, 3, 32, 32])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As we can see, each batch consists of 128 images, just as specified. However, one thing to keep in mind though is that\n",
    "PyTorch uses a different image layout (which is more efficient when working with CUDA); here, the image axes are \"num_images x channels x height x width\" (NCHW) instead of \"num_images height x width x channels\" (NHWC):"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To visually check that the images that coming of the data loader are intact, let's swap the axes to NHWC and convert an image from a Torch Tensor to a NumPy array so that we can visualize the image via `imshow`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([32, 32, 3])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "one_image = x[99].permute(1, 2, 0)\n",
    "one_image.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# note that imshow also works fine with scaled\n",
    "# images in [0, 1] range.\n",
    "plt.imshow(one_image.to(torch.device('cpu')));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch       1.0.0\n",
      "pandas      0.23.4\n",
      "imageio     2.4.1\n",
      "numpy       1.15.4\n",
      "torchvision 0.2.1\n",
      "scipy       1.1.0\n",
      "PIL.Image   5.3.0\n",
      "matplotlib  3.0.2\n",
      "\n"
     ]
    }
   ],
   "source": [
    "%watermark -iv"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  },
  "toc": {
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
